package com.hzw.code.security.config;

import com.hzw.code.redis.dao.RedisDao;
import com.hzw.code.security.filter.LoginAuthFilter;
import com.hzw.code.security.filter.PreAuthFilter;
import com.hzw.code.security.handler.CustomAccessDeniedHandler;
import com.hzw.code.security.handler.CustomLogoutSuccessHandler;
import com.hzw.code.security.handler.UnAuthorizedEntryPoint;
import com.hzw.code.security.model.CustomUserDetails;
import com.hzw.code.security.service.CustomUserDetailsService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

/**
 * spring security 配置
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true,securedEnabled=true,jsr250Enabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    private final CustomUserDetailsService userDetailsService;
    private final RedisDao<String,String> tokenRedis;
    private final RedisDao<String, CustomUserDetails> userRedis;
    private final UnAuthorizedEntryPoint unAuthorizedEntryPoint;

    public SecurityConfiguration(CustomUserDetailsService userDetailsService,
                                 RedisDao<String,String> tokenRedis,
                                 RedisDao<String, CustomUserDetails> userRedis,
                                 UnAuthorizedEntryPoint unAuthorizedEntryPoint) {
        this.userDetailsService = userDetailsService;
        this.tokenRedis = tokenRedis;
        this.userRedis = userRedis;
        this.unAuthorizedEntryPoint = unAuthorizedEntryPoint;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 设置自定义的userDetailsService
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * description: http细节
     *
     * @param http
     * @return void
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 开启跨域资源共享
        http.cors()
                .and()
                // 关闭csrf
                .csrf().disable()
                .authorizeRequests().antMatchers("/swagger-ui.html","/swagger-resources/**","/webjars/springfox-swagger-ui/**","/v2/**").permitAll()
                .antMatchers(HttpMethod.OPTIONS,"/**").permitAll().anyRequest().authenticated().and()
                // 关闭session
                .exceptionHandling().authenticationEntryPoint(unAuthorizedEntryPoint).and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                // 添加到过滤链中
                // 先是UsernamePasswordAuthenticationFilter用于login校验
                .addFilter(new LoginAuthFilter(authenticationManager(),tokenRedis,userRedis));
        http.addFilterBefore(new PreAuthFilter(userRedis,tokenRedis), UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    public AccessDeniedHandler accessDeniedHandler() {
        return new CustomAccessDeniedHandler();
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
        return source;
    }

}
